
;*******************************************************
;
;	SCSI Driver 'Status' filter.
;
;	Written by Matt Gulick.		Started August 12,1988
;
;	Copyright Apple Computer, Inc. 1988,89
;
;*******************************************************

;*******************************************************
;
;	This file contains the 'Status' filter as defined
;	in the ERS.
;
;*******************************************************

;*******************************************************
;
;	Revision History:
;
;*******************************************************

;	Aug 12,		1988	File started.
;	April 17,	1989	Made changes to accomadate the
;						Scanner Driver.

				STRING		PASCAL
				BLANKS		OFF
				PAGESIZE	70
				PRINT		NOGEN
				PRINT		NOMDIR
				MACHINE		M65816

				IMPORT		bitmap
				IMPORT		rpm_blk_num
				IMPORT		stat_cont
				IMPORT		rebuild
				IMPORT		read_pm_blk

				IMPORT		call_type
				IMPORT		main_drvr
				IMPORT		internal
				IMPORT		f_partition
				IMPORT		test_unit_rdy
				IMPORT		rqst_sense
				IMPORT		mode_sense
				IMPORT		read_capacity
				IMPORT		t_dvc_blocks
				IMPORT		set_512_mode
				IMPORT		open_flag
				IMPORT		set_our_dp
				IMPORT		disk_switch
				IMPORT		set_disk_sw
				IMPORT		rebld_dibs
				IMPORT		unit_state
				IMPORT		trash_it
				IMPORT		uses_dc
				IMPORT		dib_data_struct
				IMPORT		lst_rslt_ec		;Status
				IMPORT		lst_rslt_id		;Status
				IMPORT		lst_rslt_stat	;Status
				IMPORT		lst_rslt_skey	;Status
				IMPORT		lst_rslt_info	;Status
				IMPORT		lst_rslt_rqlen	;Status
				IMPORT		lst_rslt_scode	;Status
				IMPORT		sense_data
				IMPORT		auto_sense_data
				IMPORT		internal_buff
				IMPORT		display_cnt
				IMPORT		current_fmt
				IMPORT		opt1_blk_cnt
				IMPORT		opt1_blk_siz
				IMPORT		opt1_med_siz
				IMPORT		opt2_blk_cnt
				IMPORT		opt2_blk_siz
				IMPORT		opt2_med_siz
				IMPORT		opt3_blk_cnt
				IMPORT		opt3_blk_siz
				IMPORT		opt3_med_siz
				IMPORT		format_options
				IMPORT		check_532_rw

				ENTRY		dvc_status
				ENTRY		g_config_parms
				ENTRY		wait_status
				ENTRY		fmt_options
				ENTRY		read_p_map
				ENTRY		g_last_rslt

				PRINT		OFF

				INCLUDE		'scsihd.equates'
				INCLUDE		'M16.MEMORY'
				INCLUDE		'M16.UTIL'
				PRINT		ON

;-------------------------------------------------------------------------------

				IF			scsi_dtype = direct_acc	THEN

				ENTRY		gdp
				ENTRY		gvp

				ENDIF

;-------------------------------------------------------------------------------

				EJECT
			
;*******************************************************
;
;	Main Entry point to the 'Status' filter.  This
;	"Filter" is called when a Status Command comes in.
;	See the headers of the seperate sections for the
;	details of the commands.
;
;	Inputs:		[dib_ptr]	=	Last DIB built		(LONG)
;				Acc			=	Unspecified
;				Carry		=	Unspecified
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Outputs:	Acc			=	DRVR_BUSY
;				Carry		=	1
;						unless we have no more dibs then
;				Acc			=	0
;				Carry		=	0
;
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	GS/OS Direct Page
;				Data Bank	=	Ours
;
;	Errors:		See Spec.
;
;*******************************************************

				EXPORT	status
status			PROC
										;
										; Check to see if this is a Get Last Result
										; call.  If so, then don't worry yet about
										; getting the Unit State.
										;
				lda		<cont_code
				cmp		#$0005
				beq		@status
										;
										; Is the device Removable?
										;
				ldy		#dib.dvcchar

				lda		[dib_ptr],y
				and		#removable
				beq		@online			;No.
										;
										; This device is removable.  Now we
										; need to check to see if the unit
										; has gone offline, (then we need to
										; report that to the OS) or if the
										; unit has come back online (Rebuild
										; the DIBs).
										;
				jsr		unit_state
				bcc		@online
										;
										; Check to see if this is a Device Status.
										; If so, then don't worry yet about returning
										; the Error State.
										;
				tay
				lda		<cont_code
				beq		@status
				cmp		#$0004
				blt		@status
				bpl		@tya_out
				cmp		#$8040
				blt		@status
;				bmi		@status
@tya_out		tya						;The Carry Bit is still set.
				rts
										;
										; Check to see if this is a Device Specific
										; Status call.  If so, then don't worry
										; about it being Offline
										;
@online			lda		<cont_code
				beq		@status
				bmi		@status
										;
										; Is the device online?
										;
				ldy		#dib.dvcflag

				lda		[dib_ptr],y
				and		#dvc_online
				bne		@status			;Yes.
										;
										; Device is currently offline.
										;
				lda		#drvr_off_line
				sec
@rts_out		rts
										;
										; Zero out the Data Chaining Flag
										;
@status			stz		|uses_dc
										;
										; Clear transfer count.
										;
				lda		#null
				ldy		#dib.trx_len
				sta		[dib_ptr],y
				ldy		#dib.trx_len+2
				sta		[dib_ptr],y
										;
										; Entry to the Status Call Filter.
										; This filter acts as a mini driver.
										; It examines the Status Code sent
										; and calls the appropriate routines.
										; If the Command is $8000 or greater,
										; then it will be routed to the device
										; specific section.
										;
				lda		<stat_code
				bmi		@do_dvc_spec	;Device Specific Code.
										;
										; Check the range of the command.
										;
				cmp		#max_s_cmd+1
				bge		@error
										;
										; Convert to an index
										;
				asl		a
				tax
				jsr		(@ncmd_tbl,x)
				rts
										;
										; Bad Command Error.
										;
@error			lda		#drvr_bad_req
				sec
				rts
										;
										; Normal Command Table.
										;
@ncmd_tbl		dc.w	dvc_status		;Coded
				dc.w	g_config_parms	;Coded
				dc.w	wait_status		;Coded
				dc.w	fmt_options		;Coded
				dc.w	read_p_map		;Coded
				dc.w	g_last_rslt		;Coded
										;
										; Device Specific Code handling
										; starts here.
										;
@do_dvc_spec
;-------------------------------------------------------------------------------

				IF			scsi_dtype = direct_acc	THEN

				cmp		#$F000
				blt		@do_scsi_cmd
				and		#$00ff
				cmp		#max_config_cmd+1
				bge		@error
										;
										; Convert to an index
										;
				asl		a
				tax
				jsr		(@c_cmd_tbl,x)
				rts
										;
										; Config Command Table.
										;
@c_cmd_tbl		dc.w	gdp				;Coded (Get Disk Parms)
				dc.w	gvp				;Coded (Get Volume Parms)

@do_scsi_cmd

				ENDIF

;-------------------------------------------------------------------------------

										;
										; Check version of data structure
										;
				stz		@chk_zero		;Precondition the flag to no check
				lda		[buff_ptr]
				beq		@version_0
				cmp		#$0001
				bne		@error
										;
										; Version 1.  Preserve the data pointer
										; currently used in the DIB and replace
										; it with a pointer to the USER supplied
										; Data Chaining instructions.
										;
				clc
				ldy		#dib.trx_ptr
				lda		[dib_ptr],y
				sta		|dib_data_struct

				lda		<buff_ptr
				adc		#ds.DCcode		;Offset to first D.C. Data
				sta		[dib_ptr],y

				ldy		#dib.trx_ptr+2
				lda		[dib_ptr],y
				sta		|dib_data_struct+2

				lda		<buff_ptr+2
				adc		#^ds.DCcode
				sta		[dib_ptr],y
										;
										; Set flag to indicate that D.C. Commands
										; were used and that we need to restore
										; the pointer in the DIB to the normal
										; data descriptor.  Also set the flag to
										; indicate that we need to check the first
										; buffer pointer for Zero.
										;
				dec		|uses_dc
				dec		@chk_zero
										;
										; Do the rest normally and check the above
										; flag later.
										;
@version_0		clc
				lda		<buff_ptr
				adc		#$0002
				sta		<scsi_mdrvr

				lda		<buff_ptr+2
				adc		#null
				sta		<scsi_mdrvr+2
										;
										; Check the buffer pointer for Null.
										;
				ldy		#$000C
				lda		[scsi_mdrvr],y
				sta		<buff_ptr
				ldy		#$000C+2
				lda		[scsi_mdrvr],y
				sta		<buff_ptr+2
										;
										; Check First Buffer for $00000000
										;
				ora		<buff_ptr
				bne		@DH_Branch
				lda		@chk_zero
				bne		@error
										;
										; Call Main Driver
										;
@DH_Branch		lda		#scsit_stat
				sta		|call_type
				jsr		|main_drvr

;-------------------------------------------------------------------------------

				IF		scsi_dtype	=	apple_cd	THEN

				bcc		@no_cd_error
				lda		auto_sense_data+\	;Was it an $82, $84, or $85 Error?
						rqst_sens.addnl_sens_code
				and		#$00ff
				cmp		#$0082			;Checking for $82 (End of User Area)
				beq		@eua
				cmp		#$0084			;Checking for $84 (Illegal Mode)
				beq		@im
				cmp		#$0085			;Checking for $85 (Bad Audio Address)
				beq		@baa
				cmp		#$00B0			;Checking for $B0 (No Media)
				beq		@no_media
										;
										; None of those.  Return I/O Error.
										;
				lda		#$0027
				sec
				bra		@exit
										;
										; End of User Area.
										; Carry is set by CMP being equal
										;
@eua			lda		#$00F0
				bra		@exit
										;
										; Illegal Mode.
										; Carry is set by CMP being equal
										;
@im				lda		#$00F1
				bra		@exit
										;
										; Bad Audio Address.
										; Carry is set by CMP being equal
										;
@baa			lda		#$00F2
				bra		@exit
										;
										; Bad Audio Address.
										; Carry is set by CMP being equal
										;
@no_media		lda		#$002f
				bra		@exit


				ELSE

;-------------------------------------------------------------------------------

				bcs		@exit

				ENDIF

;-------------------------------------------------------------------------------

				IF		scsi_dtype	=	apple_cd	THEN

@no_cd_error

				ENDIF

;-------------------------------------------------------------------------------

										;
										; Save transfer count.
										;
				ldy		#dib.trx_len
				lda		[dib_ptr],y
				sta		@call_trns_cnt
				ldy		#dib.trx_len+2
				lda		[dib_ptr],y
				sta		@call_trns_cnt+2
										;
										; Check to see if we need to handle
										; a Disk Switched Event.  If not,
										; then exit.
										;
				lda		|disk_switch
				bpl		@exit
										;
										; Don't Trash the Volumes.
										;
				jsr		rebld_dibs		;Issues a DISK_SW for each rebuilt DIB.
										;
										; Restore Direct Page Values.
										;
@exit			pha
				php
										;
										; Check the D.C. Flag
										;
				lda		|uses_dc
				beq		@set_our_zp

				ldy		#dib.trx_ptr
				lda		|dib_data_struct
				sta		[dib_ptr],y

				ldy		#dib.trx_ptr+2
				lda		|dib_data_struct+2
				sta		[dib_ptr],y
				
				stz		|uses_dc		;Reset Flag

@set_our_zp		jsr		set_our_dp
										;
										; Set transfer count.
										;
				lda		@call_trns_cnt
				sta		<trans_cnt
				lda		@call_trns_cnt+2
				sta		<trans_cnt+2
										;
										; Exit.
										;
				plp
				pla
				rts
										;
										; Data Area.
										;
@call_trns_cnt	dc.l	null			;Transfer count before we stepped on it.
@chk_zero		dc.w	null			;Check first DCMove Flag.

				ENDP

				EJECT
			
;*******************************************************
;
;	
;
;	Called via 'JSR'
;
;	Inputs:		[dib_ptr]	=	Target DIB	l	(LONG)
;				Acc			=	Unspecified
;				Carry		=	Unspecified
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Returns via 'RTS'
;
;	Outputs:	Acc			=	0
;				Carry		=	0
;	or
;				Acc			=	Error
;				Carry		=	1
;
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Errors:		See Spec.
;
;*******************************************************
			
				EXPORT	dvc_status
dvc_status		PROC
										;
										; Get Device Status Call
										;
				lda		<rqst_cnt+2
				bne		@do_max
				lda		<rqst_cnt
				cmp		#$0007
				blt		@no_odds
@do_max			lda		#$0006
@no_odds		lsr		a				;0 --> Bit 15, Bit 0 --> Carry
				bcs		@bad_rqst_cnt	;No odd byte transfers
				asl		a				;Carry <-- Bit 15, Bit 0 <-- 0
				sta		<trans_cnt
				stz		<trans_cnt+2
				bne		@at_least_2
				jmp		@clc
										;
										; Bad Request Count.
										;
@bad_rqst_cnt	lda		#drvr_bad_cnt
				rts
										;
										; Init Status to $0000
										;
@at_least_2		stz		@dvc_stat
										;
										; Is the Device Linked?
										;
				ldy		#dib.dvcchar

				lda		[dib_ptr],y
				and		#linked_dvc
				beq		@no_link		;No.

				lda		#bit_14			;Yes. Set the bit
				tsb		@dvc_stat
										;
										; Is the device busy with a pending call?
										;
@no_link		ldy		#dib.dvcflag

				lda		[dib_ptr],y
				and		#int_busy
				beq		@not_busy		;No.

;-------------------------------------------------------------------------------

				IF		character_dvc = true	THEN

										;
										; If the device is a character device,
										; and it's busy, then also set the Buffer
										; Not Empty Flag.
										;
				lda		#bit_13\
						++bit_5			;Yes. Set the bits
				tsb		@dvc_stat

				ENDIF

;-------------------------------------------------------------------------------

				IF		block_dvc = true	THEN

				lda		#bit_13			;Yes. Set the bit
				tsb		@dvc_stat

				ENDIF

;-------------------------------------------------------------------------------

										;
										; Is the Device Online?
										;
@not_busy		ldy		#dib.dvcflag

				lda		[dib_ptr],y
				and		#dvc_online
				beq		@not_online2	;No. Skip Switch flag.

				lda		[dib_ptr],y		;Also Check Hard Offline
				and		#dvc_hardofl	;Is it hard offline?
				bne		@not_online		;Yes. Do switch flag

				lda		#bit_4			;Online, Set the bit
				tsb		@dvc_stat

				lda		[dib_ptr],y		;Also Check switch flag
				and		#dvc_switch		;Is it Switched?
				pha

				lda		[dib_ptr],y		;Clear Switch Flag.
				and		#dvc_switch--\
						$ffff
				sta		[dib_ptr],y

				pla
				bne		@not_online1	;Yes. Do switch flag

				bra		@online			;Skip the following mess.

@not_online
										;
										; If the device's Online Flag is set
										; and it's Hard Offline Flag is also
										; set, then we will treat this as a
										; disk switch.
										;
				lda		[dib_ptr],y
				and		#dvc_online++\
						dvc_switch--\
						$ffff
				sta		[dib_ptr],y

@not_online1	lda		#bit_0
				tsb		@dvc_stat

@not_online2

@online

;-------------------------------------------------------------------------------

				IF		block_dvc = true	THEN

										;
										; If the device is a block device, is
										; the Device Write Protected?
										;
				ldy		#dib.dvcchar

				lda		[dib_ptr],y
				and		#write_allow
				bne		@writeable		;No.

				lda		#bit_2			;Yes. Set the bit
				tsb		@dvc_stat

				ENDIF

;-------------------------------------------------------------------------------

@writeable

;-------------------------------------------------------------------------------

				IF		block_dvc = true	THEN

										;
										; If the device is a block device, has
										; the Device been switched?
										;
				jsr		rqst_sense
				bcc		@no_error
				jmp		@switch			;Yes!
										;
										; The following lines of code commented
										; by a '****' were added because of an
										; SCSI Device that returned no error when
										; there was no media on line.  This was
										; not the correct thing for the device to
										; do.  Shame on him.  What we needed to do
										; to correct this was to get the offline
										; flag, then check to see if the device
										; returned an error.  If an error is
										; returned, then we process it normally.
										; If no error was returned and the device
										; is still ofline, then we treat it as a
										; device not ready error.  The offline will
										; be cleared when the device returns an 06
										; in the sense key.
										;
@no_error		ldy		#dib.dvcflag
				lda		[dib_ptr],y		;****
				and		#dvc_hardofl	;****
				tax						;****
										;****
				lda		|sense_data+\
						rqst_sens.sense_key
				bne		@chk_sense_key	;****
				txa						;****
				beq		@too_far
				jmp		@opened			;****
@too_far		jmp		@its_back		;****

@chk_sense_key	and		#$00ff
				cmp		#$0002
				bne		@chk_for_6
				jmp		@chk_switch


;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

				IF		scsi_dtype<>apple_cd	THEN

@chk_for_6		cmp		#$0006
				beq		@inserted

				ELSE

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

@chk_for_6		cmp		#$0006
				bne		@not_a_6

				lda		sense_data+\	;Was it a RESET?
						rqst_sens.addnl_sens_code
				and		#$00ff
				cmp		#$00b0			;Checking for $B0 (NO MEDIA)
				beq		@fixit
				and		#$00fe			;Checking for $28 (INSERTION)
				cmp		#$0028			;or $29 (RESET)
				beq		@inserted		;Yes it was.
@fixit			jmp		@chk_switch
										;
										; If the device is a CD_ROM device
										; then check to see if the SENSE KEY
										; = 5.  If so, then treat it as no
										; error.
										;
@not_a_6		cmp		#$0005
				bne		@its_bs
				jmp		@its_back
@its_bs
				ENDIF

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

				stz		<trans_cnt
				ora		#$ff00
				sec
				rts
										;
										; Rebuild the DIBs.
										;
@inserted
										;
										; Is this device linked?  If it is,
										; then we need to mark them all as
										; being online.
										;
										; Start at the headptr if non-zero.
										;
				ldy		#dib.headptr
				lda		[dib_ptr],y
				tax
				ldy		#dib.headptr+2
				lda		[dib_ptr],y
				bne		@set_pointer0	;Should not be bank 0
										;
										; Current pointer is the first.
										;
				lda		<dib_ptr+2
				ldx		<dib_ptr
										;
										; Set temp Zero Page Pointer
										;
@set_pointer0	stx		<scsi_zp0
				sta		<scsi_zp0+2
										;
										; Set the Flags.
										;
				ldy		#dib.dvcflag
				lda		[scsi_zp0],y
				and		#dvc_hardofl--\
						$ffff
				ora		#dvc_switch++\
						dvc_online++\
						dvc_hard_sw
				sta		[scsi_zp0],y
											;
											; If there is a forward device
											; pointer than get it.
											;
				ldy		#dib.fdvcptr
				lda		[scsi_zp0],y
				tax
				ldy		#dib.fdvcptr+2
				lda		[scsi_zp0],y
				bne		@set_pointer0

@turdy			jsr		test_unit_rdy		;Is it ready yet?
				bcc		@they_r_built		;Yes.
				lda		auto_sense_data+\	;Is there media in the drive?
						rqst_sens.addnl_sens_code
				and		#$00ff
				cmp		#$00b0				;Checking for $B0 (NO MEDIA)
				bne		@turdy				;No.
;				bcs		@turdy				;*************************

@they_r_built	

;-------------------------------------------------------------------------------

				IF			scsi_dtype <> mcd_40		THEN

				jsr		set_512_mode

				ENDIF						;scsi_dtype <> mcd_40

;-------------------------------------------------------------------------------

											;
											; Issue the READ CAPACITY Command.
											;
				jsr		read_capacity
				bcs		@no_capacity		;Was there an error?
											;
											; Get the Block Count (Stored
											; High >> Low.  Must be switched
											; to Low >> High).  This is the last
											; readable block number.  Add 1 to
											; it for comparison reasons.
											;
				lda		|block.count\
						+internal_buff\
						+2
				xba
				adc		#$0001				;Carry is Clear as a result
				sta		|t_dvc_blocks		;of the 'READ CAPACITY' Call
				lda		|block.count\
						+internal_buff
				xba
				adc		#null
				sta		|t_dvc_blocks+2

@no_capacity	jsr		rebld_dibs			;Rebuild DIBs and Issue a DISK_SW
				php							;for each
											;
											; Restore the origonal Direct Page
											; values.
											;
				jsr		set_our_dp
				plp
				bcc		@set_switch
				jsr		test_unit_rdy
				bcc		@set_switch
											;
											; For some reason, we cannot talk to the
											; device.  It must be offline.
											;
@chk_switch		ldy		#dib.dvcflag
				lda		[dib_ptr],y
				tax

				and		#dvc_hardofl
				bne		@opened

				txa
				and		#dvc_online--\
						$ffff
				ora		#dvc_hardofl
				sta		[dib_ptr],y

				lda		#bit_4				;Clear the Online bit
				trb		@dvc_stat

				lda		#bit_0				;Set the Switch bit
				tsb		@dvc_stat

				bra		@opened
										;
										; Set Online Bit.  If dvc_hard_sw is
										; set, then clear it and return the
										; disk switch bit.
										;
@its_back		lda		[dib_ptr],y
				pha
				and		#dvc_hard_sw
				tax
				pla
				and		#dvc_hard_sw--\
						$ffff
				sta		[dib_ptr],y
				txa
				bne		@set_switch
				bra		@opened			;Back in business

@switch									;
										; Is this device linked?  If it is,
										; then we need to mark them all as
										; being offline.
										;
										; Start at the headptr if non-zero.
										;
				ldy		#dib.headptr
				lda		[dib_ptr],y
				tax
				ldy		#dib.headptr+2
				lda		[dib_ptr],y
				bne		@set_pointer2	;Should not be bank 0
										;
										; Current pointer is the first.
										;
				lda		<dib_ptr+2
				ldx		<dib_ptr
										;
										; Set temp Zero Page Pointer
										;
@set_pointer2	stx		<scsi_zp0
				sta		<scsi_zp0+2
										;
										; Set the Flags.
										;
				ldy		#dib.dvcflag
				lda		[scsi_zp0],y
				ora		#dvc_switch++\
						dvc_online++\
						dvc_hard_sw
				and		#dvc_online--\
						$ffff
				sta		[scsi_zp0],y
										;
										; If there is a forward device
										; pointer than get it.
										;
				ldy		#dib.fdvcptr
				lda		[scsi_zp0],y
				tax
				ldy		#dib.fdvcptr+2
				lda		[scsi_zp0],y
				bne		@set_pointer2
				
										;
										; Set the Switched Bit in Status
										;
@set_switch		lda		#bit_0			;Yes. Set the bit
				tsb		@dvc_stat
										;
										; No forward pointer.  Continue on.
										;
				ENDIF

;-------------------------------------------------------------------------------

@opened

;-------------------------------------------------------------------------------

				IF		character_dvc = true	THEN
										;
										; If the device is a character device,
										; has the Device been opened?
										;
				lda		|open_flag
				beq		@not_open		;No.

				lda		#bit_0			;Yes. Set the bit
				tsb		@dvc_stat

@not_open

				ENDIF

;-------------------------------------------------------------------------------

										;
										; If it is switched, then call disk switch.
										;
				lda		@dvc_stat
				and		#bit_0+bit_4	;If Online Bit is set then
				cmp		#bit_0			;don't call disk switch
				bne		@no_call
				jsr		set_disk_sw
										;
										; Return the combined flags.
										; 
@no_call		lda		<rqst_cnt+2
				bne		@its_big
				lda		<rqst_cnt
				beq		@clc
				cmp		#$0007
				blt		@no_odds_1
@its_big		lda		#$0006
@no_odds_1		and		#$fffe			;No odd byte transfers
				sta		<trans_cnt
				stz		<trans_cnt+2

				tax
				lda		@dvc_stat
				sta		[buff_ptr]
										;
										; Return the Block Count.
										;
				dex
				dex
				beq		@clc

				ldy		#dib.blkcnt
				lda		[dib_ptr],y
				ldy		#$0002
				sta		[buff_ptr],y

				dex
				dex
				beq		@clc

				ldy		#dib.blkcnt+2
				lda		[dib_ptr],y
				ldy		#$0004
				sta		[buff_ptr],y
										;
										; Exit real nice like.
										;
@clc			clc
				rts
										;
										; Data for this call.
										;
@dvc_stat		dc.w	null

				ENDP

				EJECT
			
;*******************************************************
;
;	'g_config_parms'
;
;	Called via 'JSR'
;
;	Inputs:		[dib_ptr]	=	Target DIB	l	(LONG)
;				Acc			=	Unspecified
;				Carry		=	Unspecified
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Returns via 'RTS'
;
;	Outputs:	Acc			=	0
;				Carry		=	0
;	or
;				Acc			=	Error
;				Carry		=	1
;
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Errors:		See Spec.
;
;*******************************************************

				EXPORT	g_config_parms
g_config_parms	PROC
										;
										; Get Config Parms Call
										;
				lda		#null
				sta		<trans_cnt
				sta		<trans_cnt+2
				clc
				rts

;-------------------------------------------------------------------------------

				IF			scsi_dtype = direct_acc	THEN

				INCLUDE		'SCSI Get Vol/Disk'

				ENDIF

;-------------------------------------------------------------------------------

				ENDP

				EJECT
			
;*******************************************************
;
;	Get the current Wait/No Wait status of this device.
;	If it is a block device then no error will occur and
;	a $0000 (Wait Mode) will be returned.
;
;	Called via 'JSR'
;
;	Inputs:		[dib_ptr]	=	Target DIB	l	(LONG)
;				Acc			=	Unspecified
;				Carry		=	Unspecified
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Returns via 'RTS'
;
;	Outputs:	Acc			=	0
;				Carry		=	0
;	or
;				Acc			=	Error
;				Carry		=	1
;
;				[buff_ptr]	=	Current Mode
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Errors:		See Spec.
;
;*******************************************************
			
				EXPORT	wait_status
wait_status		PROC
									;
									; Check the parameters list.
									; Should contain a WORD
									;
				lda		<rqst_cnt
				cmp		#$0002
				bne		@bad_parm
				sta		<trans_cnt

;-------------------------------------------------------------------------------

				IF 		block_dvc = true	THEN
									;
									; If a Block Device then return Wait Mode.
									;
				lda		#null

				ENDIF

;-------------------------------------------------------------------------------

				IF 		character_dvc = true	THEN
									;
									; Check the Current Mode
									;
				ldy		#dib.dvcflag
				lda		[dib_ptr],y
				and		#wait_mode
				bne		@wait
									;
									; Return No Wait Mode.
									;
				lda		#bit_15
				bra		@exit
									;
									; Return Wait Mode.
									;
@wait			lda		#null

				ENDIF

;-------------------------------------------------------------------------------

									;
									; Save it and exit.
									;
@exit			sta		[buff_ptr]
				lda		#null		;Clear the Acc.
				clc
				rts
									;
									; Bad Parm Error
									;
@bad_parm		lda		#drvr_bad_parm
				sec
				rts

				ENDP

				EJECT
			
;*******************************************************
;
;	Get Format Options Call
;
;	Called via 'JSR'
;
;	Inputs:		[dib_ptr]	=	Target DIB	l	(LONG)
;				Acc			=	Unspecified
;				Carry		=	Unspecified
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Returns via 'RTS'
;
;	Outputs:	Acc			=	0
;				Carry		=	0
;	or
;				Acc			=	Error
;				Carry		=	1
;
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Errors:		See Spec.
;
;*******************************************************
			
				EXPORT	fmt_options
fmt_options		PROC

;-------------------------------------------------------------------------------

				IF			block_dvc = true\
				AND			character_dvc = false		THEN

;-------------------------------------------------------------------------------

				IF			scsi_dtype = apple_cd		THEN
											;
											; If the device is a CD_ROM, then there
											; are no format options.
				stz		<trans_cnt
				stz		<trans_cnt+2
				lda		#bad_dev_number
				sec
				rts

				ENDIF						;scsi_dtype = apple_cd

;-------------------------------------------------------------------------------

				IF			scsi_dtype = mcd_40	THEN
											;
											; If the device is a Tape, then there
											; are no format options.
				stz		<trans_cnt
				stz		<trans_cnt+2
				lda		#null
				clc
				rts

				ENDIF						;scsi_dtype = mcd_40

;-------------------------------------------------------------------------------

				IF			scsi_dtype = direct_acc	THEN
											;
											; Get Format Options Call
											;
											; It's a block device.  But is
											; it partitioned?  If it has a
											; zero start block then there is
											; no partition.
											;
				ldy		#dib.start_blk
				lda		[dib_ptr],y
				ldy		#dib.start_blk+2
				ora		[dib_ptr],y
				beq		@no_link
											;
											; Well, it is a partition.  But is it
											; the only partition.  By this, I mean,
											; is it a disk with a partition map
											; containing only two entries, one for
											; the partition map and the other for
											; a single volume?
											;
											; Is it linked?  Let's see.
											;
				ldy		#dib.dvcchar
				lda		[dib_ptr],y
				and		#linked_dvc
				bne		@linked				;Linked.
											;
											; Now check if this is the first or
											; second entry in the Partition Map.
											;
				ldy		#dib.part_blk
				lda		[dib_ptr],y
				xba
				cmp		#$0003
				blt		@no_link			;Only one partition.

@linked			stz		<trans_cnt
				stz		<trans_cnt+2
				lda		#null
				clc
				rts
											;
											; Set display count to 3
											;
@no_link		lda		#$0003
				sta		|display_cnt-2
				sta		|display_cnt
											; 
											; Issue MODE SENSE Call
											;
				jsr		mode_sense
											;
											; Check to see if the device supports
											; the page discriptors.
											;
				lda		|mode.blk_disc\
						+internal_buff
				and		#$00ff
				beq		@do_from_dib
											;
											; Not all device return the block count
											; in this call.  Shame on them.  If the
											; block count is missing, then get it
											; from the DIB.  This data is 3 bytes
											; MSB >> LSB formatted.
											;
				lda		|mode.blocks\		;High Byte
						+internal_buff\
						-1
				and		#$ff00
				ora		|mode.blocks\		;.OR.ed with the Low Word
						+internal_buff\
						+1
				beq		@do_from_dib
											;
											; MODE SENSE is legal.  Use it.
											;
											; Set Block Count in format
											; option list.
											;
				lda		|mode.blocks\
						+internal_buff\
						+1
				xba
				sta		|opt1_blk_cnt
				sta		|opt2_blk_cnt

				lda		|mode.blocks\
						+internal_buff\
						-1
				xba
				sta		|opt1_blk_cnt+2
				sta		|opt2_blk_cnt+2
											;
											; Set Block Size in format
											; option list.
											;
				lda		|mode.blk_size\
						+internal_buff\
						+1
				xba
				cmp		#$0214				;is it = 532?
				bne		@not_532			;No.
				lda		#$0200				;Yes.
@not_532		sta		|opt1_blk_siz
				sta		|opt2_blk_siz
				bra		@set_med_size
											;
											; Set Block Count in format
											; option list from DIB.
											;
@do_from_dib	ldy		#dib.blkcnt
				lda		[dib_ptr],y
				sta		|opt1_blk_cnt
				sta		|opt2_blk_cnt

				ldy		#dib.blkcnt+2
				lda		[dib_ptr],y
				sta		|opt1_blk_cnt+2
				sta		|opt2_blk_cnt+2
											;
											; Set Block Size in format
											; option list.
											;
				ldy		#dib.blksize
				lda		[dib_ptr],y
				sta		|opt1_blk_siz
				sta		|opt2_blk_siz
											;
											; Set Media Size in format
											; option list.
											;
@set_med_size	lda		|opt1_blk_cnt+3
				and		#$00ff
				sta		@t_blocks
				lda		|opt1_blk_cnt+1
				lsr		@t_blocks
				lsr		a
				lsr		@t_blocks
				lsr		a
				lsr		@t_blocks
				lsr		a
				adc		#$0000
				sta		|opt1_med_siz
				sta		|opt2_med_siz
											;
											; Get Read Capacity
											;
				jsr		read_capacity
											;
											; Set Block Size in format
											; option list.
											;
				lda		|block.size\
						+internal_buff\
						+2
				xba
				sta		|opt3_blk_siz
				cmp		#$0200
				bne		@over
											;
											; Set display count to 2
											;
				lda		#$0002
				sta		|display_cnt-2
				sta		|display_cnt
											;
											; Set Block Count in format
											; option list.
											;
@over			lda		|block.count\
						+internal_buff\
						+2
				xba
				sta		|opt3_blk_cnt

				lda		|block.count\
						+internal_buff
				xba
				sta		|opt3_blk_cnt+2
											;
											; Set Media Size in format
											; option list.
											;
				lda		|block.count\
						+internal_buff\
						-1
				xba
				sta		@t_blocks
				lda		|block.count\
						+internal_buff\
						+1
				xba
				lsr		@t_blocks
				lsr		a
				lsr		@t_blocks
				lsr		a
				lsr		@t_blocks
				lsr		a
				adc		#$0000
				sta		|opt3_med_siz
											;
											; Restore Direct Page
											;
				jsr		set_our_dp
											;
											; Check Count range
											;
				lda		<rqst_cnt+2
				bne		@do_max
				lda		<rqst_cnt
				cmp		#opt3_med_siz-\
						format_options+\
						2
				blt		@this_many
@do_max			lda		#opt3_med_siz-\
						format_options+\
						2
											;
											; Send this many bytes of the list.
											;
@this_many		sta		<trans_cnt
				stz		<trans_cnt+2
				tay
				dey
				bmi		@exit
				short
@loop			lda		format_options,y
				sta		[buff_ptr],y
				dey
				bpl		@loop
				longmx
											;
											; Exit.
											;
@exit			lda		#null
				clc
				rts
											;
											; Data Area
											;
@t_blocks		dc.w	null

				ENDIF						;scsi_dtype = direct_acc

;-------------------------------------------------------------------------------

				ENDIF						;block_dvc = true

;-------------------------------------------------------------------------------

				IF			block_dvc = false\
				AND			character_dvc = true		THEN
											;
											; If the device is a Character Device,
											; then there are no Format Options to
											; return.
											;
				stz		<trans_cnt
				stz		<trans_cnt+2
				lda		#null
				clc
				rts

				ENDIF						;character_dvc = true

;-------------------------------------------------------------------------------

				ENDP

				EJECT
			
;*******************************************************
;
;	Most be the first device in a link!!!!
;
;	Entry point to the 'Read PMap' call.  This call
;	takes the information given by the caller on direct
;	page and builds the equivilent to a Read Status Call
;	to read request count bytes starting at physical
;	block number 1.  This is done by setting the high
;	bit of the partition call flag 'f_partition'.
;
;			Block Size				=	dib.blksize
;
;	We now Build the SCSI Main Driver Command and send
;	it.
;
;	The following will be validated by the Main Driver
;	when it builds the command. 
;
;			Request Count			=	Block Size * i
;			Block Number			=	Blk Num (No Offset)
;				This is for partitions.
;
;	After calling the Main driver and if no errors were
;	encountered, then the Transfer count will be
;	updated.
;
;	Called via 'JSR'
;
;	Inputs:		[dib_ptr]	=	Target DIB	l	(LONG)
;				Acc			=	Unspecified
;				Carry		=	Unspecified
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Returns via 'RTS'
;
;	Outputs:	Acc			=	0
;				Carry		=	0
;	or
;				Acc			=	Error
;				Carry		=	1
;
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Errors:		See Spec.
;
;*******************************************************

				EXPORT	read_p_map
read_p_map		PROC

;-------------------------------------------------------------------------------

				IF			block_dvc = true\
				AND			character_dvc = false		THEN

;-------------------------------------------------------------------------------

				IF			scsi_dtype = apple_cd		THEN
											;
											; Exit No Error.
											;
				lda		#drvr_bad_code
				sec
				rts

				ENDIF						;scsi_dtype = apple_cd

;-------------------------------------------------------------------------------

				IF			scsi_dtype = mcd_40	THEN
											;
											; Exit No Error.
											;
				lda		#drvr_bad_code
				sec
				rts

				ENDIF						;scsi_dtype = mcd_40

;-------------------------------------------------------------------------------

				IF			scsi_dtype = direct_acc	THEN

				stz		@do_532
											;
											; Set the Block size on Direct Page.
											; It is not placed there for this call,
											; and we should not rely on it being
											; left behind by the last call.
											;
				lda		#block_size
				sta		<blk_size
											;
											; Check if first DIB in link if any.
											; If it is zero, then we are already
											; there.  If not then error out.
											;
				ldy		#dib.headptr+2
				lda		[dib_ptr],y
				ldy		#dib.headptr
				ora		[dib_ptr],y
				bne		@bad_dev_num
											;
											; Let's check the request count.  If
											; this is $00000000, then exit clean
											; with no data transfered.
											;
				lda		<rqst_cnt
				ora		<rqst_cnt+2
				bne		@cnt_non_zero
				jmp		@out_of_here
											;
											; Verify Block Size.
											;
@cnt_non_zero	ldy		#dib.blksize
				lda		[dib_ptr],y			;Block Size
				cmp		<blk_size
				bne		@chk_532

				ldy		#dib.blksize+2
				lda		[dib_ptr],y
				beq		@blk_size_ok

@bad_parm		lda		#drvr_bad_parm
				sec
				rts
											;
											; Check for 532 byte block size
											;
@chk_532		tax

				lda		<blk_size
				cmp		#block_size
				bne		@bad_parm

				cpx		#$0214
				bne		@bad_parm
				dec		@do_532

@blk_size_ok
											;
											; Build the (Read Data)
											; Status Command $8008
											;
				lda		#$0001				; Sent to me Low >> High.
				xba							; I Send it out High >> Low.
				sta		|c_block_num
											;
											; Set Main Driver Pointer to
											; our data for the command.
											;
				lda		#cmd_$8008
				sta		<scsi_mdrvr
				lda		#^cmd_$8008
				sta		<scsi_mdrvr+2
											;
											; Set the Partition call flag
											;
				dec		|f_partition
											;
											; Call Main Driver
											;
				lda		#scsit_stat
				sta		|call_type
											;
											; Issue the call.
											;
				jsr		check_532_rw
				bcs		@rts
											;
											; Update Transfer Count.
											;
@out_of_here	lda		<rqst_cnt
				sta		<trans_cnt
				lda		<rqst_cnt+2
				sta		<trans_cnt+2
											;
											; Exit No Error.
											;
				lda		#$0000
				clc
				rts


@bad_dev_num	lda		#bad_dev_number
				sec
@rts			rts
											;
											; Variables and storage for short call.
											;
@do_532			dc.w	null				;532 byte block flag
											;
											; Command Data for this call.
											;
cmd_$8008		dc.b	$08
				dc.b	$00
c_block_num		dc.w	$0000
c_block_cnt		dc.b	$00
				dcb.b	7,$00

				ENDIF						;scsi_dtype = direct_acc

;-------------------------------------------------------------------------------

				ENDIF						;block_dvc = true

;-------------------------------------------------------------------------------

				IF			block_dvc = false\
				AND			character_dvc = true		THEN
											;
											; If the device is a Character Device,
											; then there are no Partitions to
											; read.
											;
				stz		<trans_cnt
				stz		<trans_cnt+2
				lda		#null
				clc
				rts

				ENDIF						;character_dvc = true

;-------------------------------------------------------------------------------

				ENDP

				EJECT
			
;*******************************************************
;
;	'g_last_rslt'
;
;	This call returns the Error code result of the last
;	call.  This used to inquire about the result of a
;	call that may have been executed asyncronously.  If
;	the device is busy with a pending call when this call
;	is issued, a DEVICE_BUSY Error will be returned.
;
;	Called via 'JSR'
;
;	Inputs:		[dib_ptr]	=	Target DIB	l	(LONG)
;				Acc			=	Unspecified
;				Carry		=	Unspecified
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Returns via 'RTS'
;
;	Outputs:	Acc			=	0
;				Carry		=	0
;	or
;				Acc			=	Error
;				Carry		=	1
;
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;			Users Buffer	=
;			|----------------------------------------|
;	WORD	+-			GS/OS Error Code			-+
;			|----------------------------------------|
;	WORD	+-			Device ID Number			-+
;			|----------------------------------------|
;	WORD	+-			SCSI Status Code			-+
;			|----------------------------------------|
;	WORD	+-		SCSI REQUEST SENSE sense key	-+
;			|----------------------------------------|
;	LONG	+-	MSB									-+
;			+-			Information Bytes			-+
;			+-									LSB	-+
;			|----------------------------------------|
;	WORD	+-		REQUEST SENSE data length		-+
;			|----------------------------------------|
;	WORD	+-				Reserved				-+
;			|----------------------------------------|
;
;	Errors:		Device Busy.  Only if the target device
;				currently has a call pending.
;
;*******************************************************

				EXPORT	g_last_rslt
g_last_rslt		PROC
											;
											; Is this the same device?
											;
				lda		<dev_num
				cmp		|lst_rslt_id
				bne		@bad_dvc_num
											;
											; Check if the device has a call
											; pending.
											;
				ldy		#dib.dvcflag
				lda		[dib_ptr],y
				and		#int_busy
				bne		@device_busy
											;
											; Update Transfer Count.
											;
				lda		<rqst_cnt+2
				bne		@rslt_all
				lda		<rqst_cnt
				and		#$fffe				;No odd byte transfers
				beq		@exit
				cmp		#lst_rslt_scode+2-\
						lst_rslt_ec
				blt		@set_rslt

@rslt_all		lda		#lst_rslt_scode+2-\
						lst_rslt_ec
@set_rslt		sta		<trans_cnt
				tay
				lda		#null
				sta		<trans_cnt+2
											;
											; Move the Data.
											;
				dey
				dey

@loop			lda		|lst_rslt_ec,y
				sta		[buff_ptr],y
				dey
				dey
				bpl		@loop
											;
											; Exit No Error.
											;
@exit			lda		#$0000
				clc
				rts
											;
											; Errors.
											;
@device_busy	lda		#drvr_busy
				sec
@rts			rts

@bad_dvc_num	lda		#bad_dev_number
				sec
				rts

				ENDP

				EJECT

				END
